package com.mingqijia.gassafety.webserver.utils;
import java.util.Date;

import com.mingqijia.gassafety.db.entity.OperateRecord;
import com.mingqijia.gassafety.shared.dto.LogVO;
import com.mingqijia.gassafety.shared.log.LogRecord;
import com.mingqijia.gassafety.webserver.service.OperateRecordService;
import com.mingqijia.gassafety.shared.constant.OperateRecordEnum;
import com.mingqijia.gassafety.shared.utils.ApplicationUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

import static com.mingqijia.gassafety.shared.constant.Constants.*;

@RequiredArgsConstructor
@Aspect
@Component
@Slf4j
public class LogRecordAspect {

    @Autowired
    OperateRecordService operateRecordService;

    public static final ThreadLocal<LogVO> threadLocal = new ThreadLocal<>();

    @Pointcut("@annotation(com.mingqijia.gassafety.shared.log.LogRecord)")
    public void pointcut() {
    }

    @AfterReturning("pointcut()")
    public void logAfterReturning(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        LogRecord logRecord = method.getAnnotation(LogRecord.class);
        String detail = logRecord.detail();
        String commonInfo = logRecord.commonInfo();
        Object[] args = joinPoint.getArgs();
        String consumerId = logRecord.consumerId();
        String[] parameterNames = signature.getParameterNames();
        detail = SpelUtil.parseSpEL(detail,args,parameterNames);
        commonInfo = SpelUtil.parseSpEL(commonInfo,args,parameterNames);
        consumerId = SpelUtil.parseSpEL(consumerId,args,parameterNames);

        Integer operateResult = OPERATE_RESULT_SUCCESS;
        String strategyType = "";
        OperateRecordEnum operateRecordEnum = logRecord.operateType();
        LogVO logVO = threadLocal.get();
        threadLocal.remove();
        if (logVO != null){
            log.info("LogVO为：{}", logVO);
            if (!StringUtils.isEmpty(logVO.getDetail())){
                detail = detail + logVO.getDetail();
            }
            if (!StringUtils.isEmpty(logVO.getCommonInfo())){
                commonInfo = commonInfo + logVO.getCommonInfo();
            }
            if (!StringUtils.isEmpty(logVO.getStrategyType())){
                strategyType = logVO.getStrategyType();
            }
            if (!StringUtils.isEmpty(logVO.getConsumerId())){
                consumerId = logVO.getConsumerId();
            }
            if (logVO.getResultCode() != null){
                operateResult = logVO.getResultCode();
            }
            if (logVO.getOperateRecordEnum() != null) {
                 operateRecordEnum = logVO.getOperateRecordEnum();
            }
        }
        //生成日志实体
        OperateRecord operateRecord = createOperateRecord(detail, commonInfo,operateRecordEnum, operateResult, strategyType, consumerId);
        //存放到数据库
        operateRecordService.save(operateRecord);
    }

    @AfterThrowing("pointcut()")
    public void logAfterThrowing(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        LogRecord logRecord = method.getAnnotation(LogRecord.class);
        String detail = logRecord.detail();
        String commonInfo = logRecord.commonInfo();
        String consumerId = logRecord.consumerId();
        Object[] args = joinPoint.getArgs();
        String[] parameterNames = signature.getParameterNames();
        detail = SpelUtil.parseSpEL(detail,args,parameterNames);
        commonInfo = SpelUtil.parseSpEL(commonInfo,args,parameterNames);
        consumerId = SpelUtil.parseSpEL(consumerId,args,parameterNames);
        OperateRecordEnum operateRecordEnum = logRecord.operateType();
        String strategyType = "";
        LogVO logVO = threadLocal.get();
        threadLocal.remove();
        if (logVO != null){
            if (!StringUtils.isEmpty(logVO.getDetail())){
                detail = detail + logVO.getDetail();
            }
            if (!StringUtils.isEmpty(logVO.getCommonInfo())){
                commonInfo = commonInfo + logVO.getCommonInfo();
            }
            if (!StringUtils.isEmpty(logVO.getStrategyType())){
                strategyType = logVO.getStrategyType();
            }
            if (!StringUtils.isEmpty(logVO.getConsumerId())){
                consumerId = logVO.getConsumerId();
            }
            if (logVO.getOperateRecordEnum() != null) {
                operateRecordEnum = logVO.getOperateRecordEnum();
            }
        }

        //生成日志实体
        OperateRecord operateRecord = createOperateRecord(detail, commonInfo, operateRecordEnum, OPERATE_RESULT_FAIL, strategyType, consumerId);
        //存放到数据库
        operateRecordService.save(operateRecord);
    }

    private OperateRecord createOperateRecord(String detail, String commonInfo, OperateRecordEnum operateType, Integer flag, String strategyType, String consumerId) {
        OperateRecord operateRecord = new OperateRecord();
        operateRecord.setOperateType(operateType.getCode());
        StringBuilder sb = new StringBuilder();
        sb.append(operateType.getOperateInfo()).append(detail);
        if (StringUtils.isNotEmpty(sb) && '\n' == (sb.charAt(sb.length() - 1))){
            sb.deleteCharAt(sb.length() -1);
        }
        operateRecord.setDetail(sb.toString());
        operateRecord.setCommonInfo(commonInfo);
        operateRecord.setOperatorCode(ApplicationUtils.getWorkingUser().getUsername());
        operateRecord.setOperatorName(ApplicationUtils.getWorkingUser().getName());
        operateRecord.setSpId(ApplicationUtils.getWorkingSpId());
        operateRecord.setOperateResult(flag);
        operateRecord.setMenu(operateType.getMenu());
        operateRecord.setStrategyType(strategyType);
        operateRecord.setConsumerId(consumerId);
        operateRecord.setCreatedAt(new Date());
        operateRecord.setUpdatedAt(new Date());
        return operateRecord;
    }

}
